#ifndef _CPU_H
#define _CPU_H

#include "types.h"

typedef void (*INSTRUCTION_CALLBACK) ();

typedef struct instruction_t {
    /* The opcode of the instruction */
    BYTE opcode;
    /* The length of the instruction, including the opcode */
    BYTE len;
    /* The callback for processing the instruction */
    INSTRUCTION_CALLBACK callback;

} INSTRUCTION;

/* Program Counter */
static BYTE g_pc;
/* Register A */
static BYTE g_reg_a;

/* INSTRUCTION: CLA */
/* DESCRIPTION: Clears register A. */
/* LEN        : 1 */
void op_0x5a();

/* INSTRUCTION: STA */
/* DESCRIPTION: Set value to register A. */
/* LEN        : 2 */
/* OPRAND     : 1 byte, the value to be set to register A */
void op_0x5b();

/* INSTRUCTION: ADD */
/* DESCRIPTION: ADD value to register A. */
/* LEN        : 2 */
/* OPRAND     : 1 byte, the value to be added to register A */
void op_0x5c();

/* INSTRUCTION: LDA */
/* DESCRIPTION: Loads the value of register A to the specified memory location. */
/* LEN        : 2 */
/* OPRAND     : 1 byte, the address in the memory where the value should be stored */
void op_0x5d();

/* INSTRUCTION: OUT */
/* DESCRIPTION: Outputs the value located at memory 0xfe to console, in little-endian byte order */
/* LEN        : 1 */
void op_0x5e();

static INSTRUCTION g_instructions[5] = {
  {
    .opcode = 0x5a,
    .len = 1,
    .callback = op_0x5a
  },
  {
    .opcode = 0x5b,
    .len = 2,
    .callback = op_0x5b
  },
  {
    .opcode = 0x5c,
    .len = 2,
    .callback = op_0x5c
  },
  {
    .opcode = 0x5d,
    .len = 2,
    .callback = op_0x5d
  },
  {
    .opcode = 0x5e,
    .len = 1,
    .callback = op_0x5e
  }
};

static void cpu_tick(BYTE opcode);

void cpu_reset();
void cpu_cycle();

#endif
